/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.wider.foundation.concurrency;

import java.util.BitSet;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author William
 */
public class BlockingRingBuffer {
        private int         ringlen;
        private int         bufsize;
        private int         hiwater;
        private int         lowater;
        private byte[][]    buffers;
        private final CountedBlockingQueue<byte[]>      freebuff;
        private final CountedBlockingQueue<byte[]>      bufinuse;

        public BlockingRingBuffer(int ring_length, int buff_size){
            ringlen = ring_length;
            bufsize = buff_size;
            lowater = ring_length / 3;
            hiwater = lowater * 2;
            buffers = new byte[ringlen][bufsize];
            freebuff    = new CountedBlockingQueue<byte[]>(ringlen);
            bufinuse    = new CountedBlockingQueue<byte[]>(ring_length);
            for (int i = 0; i < buffers.length; i++){
                freebuff.offer(buffers[i]);
            }
            System.out.println("hi: " + hiwater + ", lo: " + lowater);
        }

        public byte[] reserveForWrite() throws InterruptedException{
            return freebuff.fetch();
        }

        public void releaseFromWrite(byte[] buf) throws InterruptedException{
            while (!bufinuse.offer(buf)){
                System.out.println("Release from Write: bufinuse is full!!!");
                synchronized(bufinuse){
                    bufinuse.wait(600);
                }
            }
            if (bufinuse.size() > hiwater){
                Thread.yield();
            }
        }

        public byte[] reserveForRead() throws InterruptedException{
            return  bufinuse.fetch();
        }

        public void releaseFromRead(byte[] buf){
            freebuff.offer(buf);
            if (bufinuse.size() < lowater){
                Thread.yield();
            }
        }
}
